package com.tencent.wxcloudrun.service.business.map;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DatePattern;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.tencent.wxcloudrun.config.CustomException;
import com.tencent.wxcloudrun.config.UserContext;
import com.tencent.wxcloudrun.pojo.bo.HouseStatusEnum;
import com.tencent.wxcloudrun.pojo.bo.MediaInfo;
import com.tencent.wxcloudrun.pojo.bo.NoticeConstant;
import com.tencent.wxcloudrun.pojo.bo.SonStateZuFangEnum;
import com.tencent.wxcloudrun.pojo.dto.req.SearchMapReq;
import com.tencent.wxcloudrun.pojo.dto.resp.GetCityTagResp;
import com.tencent.wxcloudrun.pojo.dto.resp.GetHouseDetailResp;
import com.tencent.wxcloudrun.pojo.dto.resp.MapPoint;
import com.tencent.wxcloudrun.pojo.dto.resp.UdIdToListResp;
import com.tencent.wxcloudrun.pojo.po.*;
import com.tencent.wxcloudrun.service.*;
import com.tencent.wxcloudrun.service.business.MapCloudService;
import com.tencent.wxcloudrun.service.business.NoticeService;
import com.tencent.wxcloudrun.service.business.fangdong.HouseManageService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
@Slf4j
public class MapService {

    @Resource
    private MapCloudService mapCloudService;

    @Resource
    private HouseManageService houseManageService;

    @Resource
    private XConstantService xConstantService;

    @Resource
    private XHouseInfoService xHouseInfoService;

    @Resource
    private XHouseTagService xHouseTagService;

    @Resource
    private XPersonInfoService xPersonInfoService;

    @Resource
    private XApplyMiddleService xApplyMiddleService;

    @Resource
    private XTodoInfoService xTodoInfoService;

    @Resource
    private XHelpmateInfoService xHelpmateInfoService;

    @Resource
    private NoticeService noticeService;

    @Resource
    private XCloudPointService xCloudPointService;

    /**
     * 城市标签
     */
    public List<GetCityTagResp> getCityTag() {
        JSONObject city = houseManageService.getCity();
        List<GetCityTagResp> respList = new ArrayList<>();
        ArrayList<String> strings = new ArrayList<>(city.keySet());
        LambdaQueryWrapper<XConstant> xConstantLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xConstantLambdaQueryWrapper.eq(XConstant::getType01, "basic_city");
        xConstantLambdaQueryWrapper.eq(XConstant::getOpenFlag, "open");
        List<XConstant> basicCity = xConstantService.list(xConstantLambdaQueryWrapper);
        for (String string : strings) {
            GetCityTagResp getCityTagResp = new GetCityTagResp();
            getCityTagResp.setCity(string);
            XConstant xConstant = basicCity.stream().filter(var -> string.equals(var.getKey01())).collect(Collectors.toList()).get(0);
            getCityTagResp.setLng(Double.valueOf(xConstant.getValue01()));
            getCityTagResp.setLat(Double.valueOf(xConstant.getValue02()));
            respList.add(getCityTagResp);
        }
        return respList;
    }

    public String getCurCity(Double lng, Double lat) {
        JSONObject jsonObject = mapCloudService.geoCoder(lat, lng);
        String cityFromJSON = mapCloudService.getCityFromJSON(jsonObject).replace("市", ""); // 城市名
        List<String> cityTag = getCityTag().stream().map(GetCityTagResp::getCity).collect(Collectors.toList());
        if (cityTag.contains(cityFromJSON)) {
            return cityFromJSON;
        } else {
            return "广州";
        }
    }

    public List<MapPoint> searchMap(SearchMapReq req) {
        String radius = "20000";
        String down;
        String up;
        String tableId = houseManageService.getCity().getString(req.getCity());
        if (ObjUtil.isNull(req.getDown())) {
            down = new BigDecimal("0.00").toPlainString();
        } else {
            down = req.getDown().toPlainString();
        }
        if (ObjUtil.isNull(req.getUp())) {
            up = new BigDecimal("1000000.00").toPlainString();
        } else {
            up = req.getUp().toPlainString();
        }
        JSONObject searchNearby = mapCloudService.searchNearby(tableId, req.getLat() + "," + req.getLng(), radius, down, up);
        List<JSONObject> cloudSearchList = mapCloudService.getPointFromJSON(searchNearby);
        List<MapPoint> respList = new ArrayList<>();
        if (CollUtil.isEmpty(cloudSearchList)) {
            return respList;
        }
        List<String> udId1 = cloudSearchList.stream().map(var -> String.valueOf(var.getInteger("udId"))).collect(Collectors.toList());
        // 一个 udId 对应地图上的一个点，这个点可能对应多个房源，如果这个点没有符合展示要求，就不能展示它
        LambdaQueryWrapper<XHouseInfo> xHouseInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHouseInfoLambdaQueryWrapper.in(XHouseInfo::getPointId, udId1);
        List<XHouseInfo> list = xHouseInfoService.list(xHouseInfoLambdaQueryWrapper);
        for (JSONObject jsonObject : cloudSearchList) {
            MapPoint mapPoint = new MapPoint();
            Integer udId = jsonObject.getInteger("udId");
            if (CollUtil.isNotEmpty(list)) {
                List<XHouseInfo> collect = list.stream().filter(var -> String.valueOf(udId).equals(var.getPointId())).collect(Collectors.toList());
                if (CollUtil.isNotEmpty(collect)) {
                    List<String> stringList = collect.stream().map(XHouseInfo::getPicAuth).filter(StrUtil::isNotBlank).collect(Collectors.toList());
                    // 首先是至少要有一个认证通过的才能予以展示
                    if (CollUtil.isEmpty(stringList)) {
                        continue; // 表明全部是一些没有认证过的房源
                    }
                    if (!stringList.contains("yes")) {
                        continue; // 表明里面一个认证通过的都没有
                    }
                    // 还必须得是可出租或预出租得才能予以展示
                    List<String> strings = collect.stream().map(XHouseInfo::getHouseState).filter(StrUtil::isNotBlank).collect(Collectors.toList());
                    if (!strings.contains(HouseStatusEnum.WAIT_RENT.getValue()) && !strings.contains(HouseStatusEnum.READY_RENT.getValue())) {
                        continue;
                    }
                }
            }
            mapPoint.setUdId(udId);
            mapPoint.setLatitude(jsonObject.getDouble("lat"));
            mapPoint.setLongitude(jsonObject.getDouble("lng"));
            respList.add(mapPoint);
        }
        return respList;
    }

    @Transactional(rollbackFor = Exception.class)
    public List<UdIdToListResp> udIdToList(String udId) {
        LambdaQueryWrapper<XHouseInfo> xHouseInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHouseInfoLambdaQueryWrapper.eq(XHouseInfo::getPointId, udId);
        xHouseInfoLambdaQueryWrapper.in(XHouseInfo::getHouseState, HouseStatusEnum.WAIT_RENT.getValue(), HouseStatusEnum.READY_RENT.getValue());
        xHouseInfoLambdaQueryWrapper.notIn(XHouseInfo::getPicAuth, "no", "ing");
        List<XHouseInfo> allByPointId = xHouseInfoService.list(xHouseInfoLambdaQueryWrapper);
        List<UdIdToListResp> respList = new ArrayList<>();
        for (XHouseInfo xHouseInfo : allByPointId) {
            UdIdToListResp udIdToListResp = new UdIdToListResp();
            udIdToListResp.setHouseInfo(xHouseInfo.getHouseName() + "_" + xHouseInfo.getFloor() + "楼_" + xHouseInfo.getMouthMoney().toPlainString() + "元");
            LambdaQueryWrapper<XHouseTag> xHouseTagLambdaQueryWrapper = new LambdaQueryWrapper<>();
            xHouseTagLambdaQueryWrapper.eq(XHouseTag::getHouseId, xHouseInfo.getHouseId());
            List<XHouseTag> allByHouseId = xHouseTagService.list(xHouseTagLambdaQueryWrapper);
            List<String> collect = allByHouseId.stream().map(XHouseTag::getTagId).limit(4).collect(Collectors.toList());
            udIdToListResp.setTagList(StrUtil.join("、", collect));
            udIdToListResp.setHouseStatus(HouseStatusEnum.findByValue(xHouseInfo.getHouseState()).getKey());
            List<MediaInfo> mediaInfoList = JSON.parseArray(xHouseInfo.getPicId(), MediaInfo.class);
            List<MediaInfo> picCol = mediaInfoList.stream().filter(var -> "jpeg".equalsIgnoreCase(HouseManageService.getLastPartAfterDot(var.getFileID())) ||
                    "jpg".equalsIgnoreCase(HouseManageService.getLastPartAfterDot(var.getFileID())) ||
                    "png".equalsIgnoreCase(HouseManageService.getLastPartAfterDot(var.getFileID()))).collect(Collectors.toList());
            udIdToListResp.setPic(picCol.get(0).getFileID());
            udIdToListResp.setIndex(xHouseInfo.getHouseId());
            respList.add(udIdToListResp);
        }
        return respList;
    }

    public GetHouseDetailResp getHouseDetail(String index) {
        LambdaQueryWrapper<XHouseInfo> xHouseInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHouseInfoLambdaQueryWrapper.eq(XHouseInfo::getHouseId, index);
        XHouseInfo oneByHouseId = xHouseInfoService.getOne(xHouseInfoLambdaQueryWrapper);
        GetHouseDetailResp getHouseDetailResp = new GetHouseDetailResp();
        getHouseDetailResp.setHouseId(oneByHouseId.getHouseId());
        getHouseDetailResp.setPicId(JSON.parseArray(oneByHouseId.getPicId(), MediaInfo.class));
        LambdaQueryWrapper<XHouseTag> xHouseTagLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHouseTagLambdaQueryWrapper.eq(XHouseTag::getHouseId, index);
        List<XHouseTag> houseTags = xHouseTagService.list(xHouseTagLambdaQueryWrapper);
        getHouseDetailResp.setTagList(houseTags.stream().map(XHouseTag::getTagId).collect(Collectors.toList()));
        if (HouseStatusEnum.NO_RENT.getValue().equals(oneByHouseId.getHouseState())) {
            getHouseDetailResp.setHouseState("不出租");
        }
        if (HouseStatusEnum.WAIT_RENT.getValue().equals(oneByHouseId.getHouseState())) {
            getHouseDetailResp.setHouseState("待出租");
        }
        if (HouseStatusEnum.READY_RENT.getValue().equals(oneByHouseId.getHouseState())) {
            getHouseDetailResp.setHouseState("预出租");
        }
        if (HouseStatusEnum.RENT.getValue().equals(oneByHouseId.getHouseState())) {
            getHouseDetailResp.setHouseState("已出租");
        }
        if (HouseStatusEnum.EXPIRE.getValue().equals(oneByHouseId.getHouseState())) {
            getHouseDetailResp.setHouseState("过期");
        }
        getHouseDetailResp.setHouseName(oneByHouseId.getHouseName());
        getHouseDetailResp.setAddress(oneByHouseId.getAddress());
        getHouseDetailResp.setFloor(oneByHouseId.getFloor());
        getHouseDetailResp.setArea(oneByHouseId.getArea());
        getHouseDetailResp.setWaterPrice(oneByHouseId.getWaterPrice());
        getHouseDetailResp.setLastWaterValue(oneByHouseId.getLastWaterValue());
        getHouseDetailResp.setPowerPrice(oneByHouseId.getPowerPrice());
        getHouseDetailResp.setLastPowerValue(oneByHouseId.getLastPowerValue());
        getHouseDetailResp.setGasPrice(oneByHouseId.getGasPrice());
        getHouseDetailResp.setLastGasValue(oneByHouseId.getLastGasValue());
        getHouseDetailResp.setMouthMoney(oneByHouseId.getMouthMoney());
        getHouseDetailResp.setDeposit(oneByHouseId.getDeposit());
        getHouseDetailResp.setManageFee(oneByHouseId.getManageFee());
        getHouseDetailResp.setHouseRemark(oneByHouseId.getHouseRemark());
        getHouseDetailResp.setFeeRemark(oneByHouseId.getFeeRemark());
        getHouseDetailResp.setUpdateTime(DateUtil.format(oneByHouseId.getUpdateTime(), DatePattern.NORM_DATETIME_FORMAT));
        LambdaQueryWrapper<XCloudPoint> xCloudPointLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xCloudPointLambdaQueryWrapper.eq(XCloudPoint::getUdId, oneByHouseId.getPointId());
        XCloudPoint pointServiceOne = xCloudPointService.getOne(xCloudPointLambdaQueryWrapper);
        getHouseDetailResp.setLat(pointServiceOne.getLat());
        getHouseDetailResp.setLng(pointServiceOne.getLng());
        getHouseDetailResp.setAuthInfo("yes".equals(oneByHouseId.getPicAuth()) ? "图片官方认证" : "");
        return getHouseDetailResp;
    }

    public String getPhone(String houseId) {
        LambdaQueryWrapper<XHouseInfo> xHouseInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHouseInfoLambdaQueryWrapper.eq(XHouseInfo::getHouseId, houseId);
        XHouseInfo oneByHouseId = xHouseInfoService.getOne(xHouseInfoLambdaQueryWrapper);
        LambdaQueryWrapper<XPersonInfo> xPersonInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xPersonInfoLambdaQueryWrapper.eq(XPersonInfo::getPersonId, oneByHouseId.getLandlordId());
        xPersonInfoLambdaQueryWrapper.eq(XPersonInfo::getPersonType, "landlord");
        XPersonInfo landlord = xPersonInfoService.getOne(xPersonInfoLambdaQueryWrapper);
        // 检查此房子是否有助理在进行管理，有的话，优先返回助理的手机号
        LambdaQueryWrapper<XHelpmateInfo> xHelpmateInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHelpmateInfoLambdaQueryWrapper.eq(XHelpmateInfo::getLandlordId, oneByHouseId.getLandlordId());
        xHelpmateInfoLambdaQueryWrapper.like(XHelpmateInfo::getHouseList, houseId);
        List<XHelpmateInfo> list = xHelpmateInfoService.list(xHelpmateInfoLambdaQueryWrapper);
        if (CollUtil.isEmpty(list)) { // 这个房子没有助理在管理，返回房东的手机号
            return landlord.getPhone();
        }
        return list.get(0).getHelpPhone(); // 有助理在管理此房子，返回助理的手机号
    }

    @Transactional(rollbackFor = Exception.class)
    public String applyHouse(String houseId, Integer num, Integer liveNum, String liveYmd) {
        String openId = UserContext.getOpenId();
        // 租客的身份信息如果不完善的话，不能发起租房
        LambdaQueryWrapper<XPersonInfo> xPersonInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xPersonInfoLambdaQueryWrapper.eq(XPersonInfo::getPersonId, openId);
        xPersonInfoLambdaQueryWrapper.eq(XPersonInfo::getPersonType, "tenant");
        XPersonInfo xPersonInfo = xPersonInfoService.getOne(xPersonInfoLambdaQueryWrapper);
        if (ObjectUtil.isNull(xPersonInfo) || StrUtil.isBlank(xPersonInfo.getCardFront()) ||
                StrUtil.isBlank(xPersonInfo.getCardBack()) || StrUtil.isBlank(xPersonInfo.getSignPic()) ||
                StrUtil.isBlank(xPersonInfo.getCardName()) || StrUtil.isBlank(xPersonInfo.getPhone()) ||
                StrUtil.isBlank(xPersonInfo.getCardId()) || StrUtil.isBlank(xPersonInfo.getSex())) {
            throw new CustomException("请先前往【租客：个人信息】完善信息后再做申请！");
        }
        LambdaQueryWrapper<XApplyMiddle> xApplyMiddleLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xApplyMiddleLambdaQueryWrapper.eq(XApplyMiddle::getTenantId, openId);
        xApplyMiddleLambdaQueryWrapper.eq(XApplyMiddle::getHouseId, houseId);
        List<XApplyMiddle> xApplyMiddleList = xApplyMiddleService.list(xApplyMiddleLambdaQueryWrapper);
        if (CollUtil.isNotEmpty(xApplyMiddleList)) {
            throw new CustomException("不可重复发起租房申请！");
        }
        LambdaQueryWrapper<XHouseInfo> xHouseInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHouseInfoLambdaQueryWrapper.eq(XHouseInfo::getHouseId, houseId);
        XHouseInfo houseInfo = xHouseInfoService.getOne(xHouseInfoLambdaQueryWrapper);
        // 未认证的房屋不能发起申请
        if (!"yes".equals(houseInfo.getPicAuth())) {
            throw new CustomException("未认证的房屋不能发起申请");
        }
        if (!HouseStatusEnum.WAIT_RENT.getValue().equals(houseInfo.getHouseState()) &&
                !HouseStatusEnum.READY_RENT.getValue().equals(houseInfo.getHouseState())) {
            throw new CustomException("此房屋暂不出租");
        }
        Date date = new Date();
        String tenantTodoId = IdUtil.getSnowflakeNextIdStr();
        String landTodoId = IdUtil.getSnowflakeNextIdStr();
        // 存租房申请中间表
        XApplyMiddle xApplyMiddle = new XApplyMiddle();
        String snowflakeNextIdStr = IdUtil.getSnowflakeNextIdStr();
        xApplyMiddle.setApplyId(snowflakeNextIdStr);
        xApplyMiddle.setTenantId(openId);
        xApplyMiddle.setLandId(houseInfo.getLandlordId());
        xApplyMiddle.setHouseId(houseId);
        xApplyMiddle.setPersonNum(num);
        xApplyMiddle.setLiveYmd(liveYmd);
        xApplyMiddle.setLiveNum(liveNum);
        xApplyMiddle.setMouthFee(houseInfo.getManageFee());
        xApplyMiddle.setDeposit(houseInfo.getDeposit());
        xApplyMiddle.setManageFee(houseInfo.getManageFee());
        xApplyMiddle.setWaterPrice(houseInfo.getWaterPrice());
        xApplyMiddle.setWaterValue(StrUtil.isBlank(houseInfo.getLastWaterValue()) ? BigDecimal.ZERO : new BigDecimal(houseInfo.getLastWaterValue()));
        xApplyMiddle.setPowerPrice(houseInfo.getPowerPrice());
        xApplyMiddle.setPowerValue(StrUtil.isBlank(houseInfo.getLastPowerValue()) ? BigDecimal.ZERO : new BigDecimal(houseInfo.getLastPowerValue()));
        xApplyMiddle.setGasPrice(houseInfo.getGasPrice());
        xApplyMiddle.setGasValue(StrUtil.isBlank(houseInfo.getLastGasValue()) ? BigDecimal.ZERO : new BigDecimal(houseInfo.getLastGasValue()));
        xApplyMiddle.setHouseRemark(houseInfo.getHouseRemark());
        xApplyMiddle.setFeeRemark(houseInfo.getFeeRemark());
        xApplyMiddle.setSonOneId(IdUtil.getSnowflakeNextIdStr());
        xApplyMiddle.setSonOneInfo("租客申请");
        xApplyMiddle.setSonOneState(SonStateZuFangEnum.SUCCESS.getValue());
        xApplyMiddle.setSonTwoId(IdUtil.getSnowflakeNextIdStr());
        xApplyMiddle.setSonTwoInfo("房东确认");
        xApplyMiddle.setSonTwoState(SonStateZuFangEnum.WAIT.getValue());
        xApplyMiddle.setSonThreeId(IdUtil.getSnowflakeNextIdStr());
        xApplyMiddle.setSonThreeInfo("租客确认");
        xApplyMiddle.setSonThreeState(SonStateZuFangEnum.WAIT.getValue());
        xApplyMiddle.setSonFourId(IdUtil.getSnowflakeNextIdStr());
        xApplyMiddle.setSonFourInfo("付款");
        xApplyMiddle.setSonFourState(SonStateZuFangEnum.WAIT.getValue());
        xApplyMiddle.setCreateTime(date);
        xApplyMiddle.setUpdateTime(date);
        xApplyMiddle.setTenantTodoId(tenantTodoId);
        xApplyMiddle.setLandTodoId(landTodoId);
        xApplyMiddleService.save(xApplyMiddle);
        // 存待办表
        XTodoInfo xTodoInfoTanent = new XTodoInfo(); // 租客
        xTodoInfoTanent.setTodoId(tenantTodoId);
        xTodoInfoTanent.setTodoRole("tenant");
        xTodoInfoTanent.setTodoOption("租房申请");
        xTodoInfoTanent.setTodoPerson(openId);
        xTodoInfoTanent.setTodoThing(snowflakeNextIdStr);
        xTodoInfoTanent.setCreateTime(date);
        XTodoInfo xTodoInfoLand = new XTodoInfo(); // 房东
        xTodoInfoLand.setTodoId(landTodoId);
        xTodoInfoLand.setTodoRole("land");
        xTodoInfoLand.setTodoOption("租房申请");
        xTodoInfoLand.setTodoPerson(houseInfo.getLandlordId());
        xTodoInfoLand.setTodoThing(snowflakeNextIdStr);
        xTodoInfoLand.setCreateTime(date);
        ArrayList<XTodoInfo> xTodoInfos = CollUtil.newArrayList(xTodoInfoTanent, xTodoInfoLand);
        xTodoInfoService.saveBatch(xTodoInfos);
        // 检查这个房子是否有助理在管理
        String landlordId = houseInfo.getLandlordId();
        LambdaQueryWrapper<XHelpmateInfo> xHelpmateInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
        xHelpmateInfoLambdaQueryWrapper.eq(XHelpmateInfo::getLandlordId, landlordId);
        xHelpmateInfoLambdaQueryWrapper.like(XHelpmateInfo::getHouseList, houseId);
        List<XHelpmateInfo> list = xHelpmateInfoService.list(xHelpmateInfoLambdaQueryWrapper);
        int helpFlag = 0; // 0表示没有助理，1表示有助理
        if (CollUtil.isNotEmpty(list)) { // 表明这间房子有助理在管理，甚至可能有多个，给他们发送通知
            for (XHelpmateInfo xHelpmateInfo : list) {
                ++helpFlag;
                noticeService.createNoticeByOpenid(xHelpmateInfo.getHelpmateId(), "helpmate",
                        NoticeConstant.APPLY_HOUSE_TO_HELP_TITLE,
                        String.format(NoticeConstant.APPLY_HOUSE_TO_HELP_CONTENT, xPersonInfo.getCardName()));
            }
        }
        // 给这个房子的房东发送一个通知
        noticeService.createNoticeByOpenid(landlordId, "land",
                NoticeConstant.APPLY_HOUSE_TO_LAND_TITLE,
                String.format(NoticeConstant.APPLY_HOUSE_TO_LAND_CONTENT, xPersonInfo.getCardName(), helpFlag == 0 ? "" : "，信息已同步至助理"));
        // 给租客生成一个通知
        noticeService.createNoticeByOpenid(openId, "tenant",
                NoticeConstant.APPLY_HOUSE_TO_TENANT_TITLE,
                String.format(NoticeConstant.APPLY_HOUSE_TO_TENANT_CONTENT));
        return "申请成功，请联系房东进行确认后即可签约。";
    }
}
